grammar plp4;

@header {
	import java.lang.String;
	import java.util.ArrayList;
}

@rulecatch {
	catch (RecognitionException e) {
		reportError(e);
		System.exit(1);
	}
}
@members {


	public boolean mainTrobat=false;
	
	public int posicionSimbolo=0;
	public int contSalto = 0;
	public int maxPila = 0;
       	 public int auxHashingName1;
        	public int auxHashingName2;
        	public boolean hayMain = false;
        	public String claseRef="",claseExpr="";
        	public boolean estaEnMain=false;

	private TablaSimbolos tActiva=null;		// La mate porque era mia
	

	public String ponBlancos(int num) {
	        String cad = "";
	        for (int i = 0; i < num * 4; i++) {
	            cad += " ";
       	 	}
        	return cad;
    	}
    	public String inicializaVectores(TablaSimbolos tb)
    	{
    		String salida = "";
    		ArrayList campos = tb.obtenCampos();
    		Simbolo sim;
   		// obtener los simbolos array que tenga la clase que queremos 'construir'
		for (int i=0;i<campos.size();i++)
		{
			sim = (Simbolo)campos.get(i);
			if (sim.esArray())
			{
			
				salida += "ldc.i4 "+ sim.obtenDimensionTotal() + "\n";
				salida += "newarr[mscorlib] System.";
				if (sim.esReal())
				{
					salida +="Double\n";
					salida +="stfld Float64[] '";
				}else
				{
					salida +="Int32\n";
					salida +="stfld Int32[] '";
					
				}
				salida+=sim.getNomClasse()+"'::'"+sim.getNombre()+"'\n";
				
			}
		}
		return salida;
    	}
    	public String constructorPorDefecto(TablaSimbolos tb){
    		String salida = "";    		
    		
    		salida+= ".method public specialname rtspecialname instance void .ctor() cil managed\n{"+
			".maxstack 15\n";			
		salida+=inicializaVectores(tb);				
		salida+= "ldarg.0\n"+
			"call instance void [mscorlib]System.Object::.ctor()\n"+
			"ret\n"+
			"}\n";
			
		return salida;
    		}

    	private void ErrorSem1(int fila, int columna, String disfunka)
	{
		columna++;
		System.err.println("Error 1 ("+fila+","+columna+"): '"+ disfunka +"' ya existe en este ambito");
		System.exit(5);
	}

	private void ErrorSem2(int fila, int columna, String disfunka)
	{
		columna++;
		System.err.println("Error 2 ("+fila+","+columna+"): simbolo '"+ disfunka +"' no ha sido declarado");
		System.exit(5);
	}

	private void ErrorSem3(int fila, int columna, String disfunka)
	{
		columna++;
		System.err.println("Error 3 ("+fila+","+columna+"): tipo incompatible en operador aritmetico '"+ disfunka +"'");
		System.exit(5);
	}

	private void ErrorSem4(int fila, int columna, String disfunka)
	{
		columna++;
		System.err.println("Error 4 ("+fila+","+columna+"): tipo incompatible en operador logico '"+ disfunka +"'");
		System.exit(5);
	}

	private void ErrorSem5(int fila, int columna, String disfunka)
	{
		columna++;
		System.err.println("Error 5 ("+fila+","+columna+"): la expresion debe ser de tipo booleano en la instruccion '"+ disfunka +"'");
		System.exit(5);
	}

	private void ErrorSem6(int fila, int columna, String disfunka)
	{
		columna++;
		System.err.println("Error 6 ("+fila+","+columna+"): tipos incompatibles en la instruccion de asignacion");
		System.exit(5);
	}

	private void ErrorSem7(int fila, int columna, String disfunka)
	{
		columna++;
		System.err.println("Error 7 ("+fila+","+columna+"): tipos incompatibles en la instruccion de lectura");
		System.exit(5);
	}

	private void ErrorSem8(int fila, int columna, String disfunka)
	{
		columna++;
		System.err.println("Error 8 ("+fila+","+columna+"): tamanyo incorrecto");
		System.exit(5);
	}
	private void ErrorSem9(int fila, int columna, String disfunka)
	{
		System.err.println("Error 9 ("+fila+","+columna+"): numero insuficiente de indices en el array '"+ disfunka +"'");
		System.exit(5);
	}


	private void ErrorSem10(int fila, int columna, String disfunka)
	{
		System.err.println("Error 10 ("+fila+","+columna+"): numero de dimensiones incorrecto");
		System.exit(5);
	}

	private void ErrorSem11(int fila, int columna, String disfunka)
	{
		System.err.println("Error 11 ("+fila+","+columna+"): el identificador '"+ disfunka +"' no es de tipo array");
		System.exit(5);
	}

	private void ErrorSem12(int fila, int columna, String disfunka)
	{
		System.err.println("Error 12 ("+fila+","+columna+"): demasiados indices");
		System.exit(5);
	}

	private void ErrorSem13(int fila, int columna)
	{
		System.err.println("Error 13 ("+fila+","+columna+"): indice de tipo incompatible");
		System.exit(5);
	}

	private void ErrorSem14(int fila, int columna, String disfunka)
	{
		System.err.println("Error 14 ("+fila+","+columna+"): tipo '" + disfunka +"' incompatible con la declaracion");
		System.exit(5);
	}

	private void ErrorSem15(int fila, int columna, String disfunka)
	{
		System.err.println("Error 15 ("+fila+","+columna+"): la variable que se intenta modificar es una variable indice");
		System.exit(5);
	}

	private void ErrorSem16(int fila, int columna, String disfunka)
	{
		System.err.println("Error 16 ("+fila+","+columna+"): instruccion '" + disfunka +"' no permitida fuera de un bucle");
		System.exit(5);
	}

	private void ErrorSem17(int fila, int columna, String disfunka)
	{
		System.err.println("Error 17 ("+fila+","+columna+"): la expresion debe ser de tipo numerico");
		System.exit(5);
	}


	private void ErrorSem18()
	{
		System.err.println("Error 18: debe existir un unico metodo Main");
		System.exit(5);
	}

	private void ErrorSem19(int fila, int columna, String disfunka)
	{
		columna++;
		System.err.println("Error 19 ("+fila+","+columna+"): identificador '"+ disfunka +"' usado incorrectamente");
		System.exit(5);
	}
	private void ErrorSem20(int fila, int columna, String disfunka)
	{
		columna++;
		System.err.println("Error 20 ("+fila+","+columna+"): el metodo '"+ disfunka +"' ya esta definido");
		System.exit(5);
	}

	private void ErrorSem21(int fila, int columna, String disfunka)
	{
		columna++;
		System.err.println("Error 21 ("+fila+","+columna+"): el metodo '"+ disfunka +"' no esta definido");
		System.exit(5);
	}

	private void ErrorSem22(int fila, int columna)
	{
		columna++;
		System.err.println("Error 22 ("+fila+","+columna+"): aqui no puede usarse return");
		System.exit(5);
	}

	private void ErrorSem23(int fila, int columna)
	{
		columna++;
		System.err.println("Error 23 ("+fila+","+columna+"): valor devuelto de tipo incompatible");
		System.exit(5);
	}

	private void ErrorSem24(int fila, int columna)
	{
		columna++;
		System.err.println("Error 24 ("+fila+","+columna+"): tipo incompatible en el parametro");
		System.exit(5);
	}

	private void ErrorSem25(int fila, int columna)
	{
		columna++;
		System.err.println("Error 25 ("+fila+","+columna+"): no se permite la declaracion de arrays de objetos");
		System.exit(5);
	}

	private void ErrorSem26(int fila, int columna, String disfunka, String disfunka2)
	{
		columna++;
		System.err.println("Error 26 ("+fila+","+columna+"): objeto '"+ disfunka +"' no es de clase '"+ disfunka2 +"'");
		System.exit(5);
	}

	private void ErrorSem27(int fila, int columna, String disfunka)
	{
		columna++;
		System.err.println("Error 27 ("+fila+","+columna+"): miembro '"+ disfunka +"' no accesible desde Main");
		System.exit(5);
	}

	private void ErrorSem28(int fila, int columna, String disfunka)
	{
		columna++;
		System.err.println("Error 28 ("+fila+","+columna+"): tamanyo incorrecto");
		System.exit(5);
	}
	private void ErrorSem29(int fila, int columna, String disfunka)
	{
		System.err.println("Error 29 ("+fila+","+columna+"): tipo incompatible en operador relacional '"+ disfunka +"'");
		System.exit(5);
	}

	private void ErrorSem30(int fila, int columna)
	{
		System.err.println("Error 30 ("+fila+","+columna+"): constructor usado incorrectamente");
		System.exit(5);
	}


	private void ErrorSem31(int fila, int columna)
	{
		System.err.println("Error 31 ("+fila+","+columna+"): un constructor no puede devolver nada");
		System.exit(5);
	}

	private void ErrorSem32(int fila, int columna)
	{
		System.err.println("Error 32 ("+fila+","+columna+"): un metodo debe devolver algo");
		System.exit(5);
	}


	public void emitErrorMessage(String mensaje)
	{
		System.err.println(mensaje);
		System.exit(1);
	}


}

@lexer::members {
	public void emitErrorMessage(String mensaje)
	{
		System.err.println(mensaje);
		System.exit(1);
	}
}


s [String entrada] returns [String eixida]
	@init{
		$eixida= "";
	}:
	{
		$eixida+= ".assembly extern mscorlib{}\n" +
			  ".assembly '"+ entrada +"'{}\n";
	}
	(
	clase{
		$eixida += $clase.eixida;
	}
	)+
	{
		if(mainTrobat==false)
		{
			ErrorSem18(); 
			//Error 18: debe existir un unico metodo Main
		}
	}
	;


clase returns [String eixida]
	@init
	{
		$eixida= "";
		String eixidaCampo="";
		String eixidaMetodo="";
		Simbolo claseActual;
		
	}:
	CLASS ID LLAVEI {
		$eixida+= ".class '"+$ID.text+"' extends [mscorlib]System.Object {\n";
		

		TablaSimbolos.anyadirClase(new Simbolo($ID.text,Simbolo.CLASE,Simbolo.ESPECIAL,0));
		claseActual = TablaSimbolos.obtenClase ( $ID.text);
		
		tActiva = claseActual.getTablaSimbolos(); // La mate porque era mia	
		
	}
	(
	// miembro son metodos y campos
	miembro
	{
		if ($miembro.eixidaCampo=="")
		{
			eixidaMetodo = $miembro.eixidaMetodo;
		}
		else
		{
			eixidaCampo += $miembro.eixidaCampo;
		}		
	}
	)+
	{
		
		if (!tActiva.obtenPadre().encontroCtorPorDefecto) 	// La mate porque era mia
		{
			eixida +=constructorPorDefecto(tActiva);
		}
		$eixida+=eixidaCampo;
		$eixida+=eixidaMetodo;
	}
	LLAVED
	{
		$eixida += "}\n";
	}
	;


miembro returns [String eixidaCampo, String eixidaMetodo]
	@init{
		$eixidaCampo= "";
		$eixidaMetodo= "";
	}:
	campo
	{
		$eixidaCampo = $campo.eixida;
	}
	|
	metodo
	{
		$eixidaMetodo =$metodo.eixida;
	}
	;

campo returns [String eixida]
	@init{
		$eixida= "";
		
	}:
	visibilidad
	decl[$visibilidad.vis]
	{
		$eixida += $decl.eixida;
	}
	;

visibilidad returns [String eixida, String vis]
	@init{
		$eixida= "";
	}:
	PRIVATE
	{
		$vis = $PRIVATE.text;
	}
	|
	PUBLIC
	{
		$vis = $PUBLIC.text;
	}
	;


metodo returns [String eixida]
	@init{
		$eixida= "";
		String ambito="constructor";
		String devuelveStrin="";
		int devuelveTipo=0;
		String fritanga="";
		String meth="";
		Simbolo simbaux;
		String tipot="";
		
	}:
	PUBLIC
	(
            	tiposimple
            	{
          		devuelveStrin=$tiposimple.tipoStrin;
          		devuelveTipo=$tiposimple.tipet;  			
          		ambito = "metodo";      
          		      			
            		if 		( devuelveTipo==Simbolo.ENTERO)  	tipot = "int32";
			else if 	( devuelveTipo==Simbolo.REAL) 		tipot = "float64";
			else if 	( devuelveTipo==Simbolo.BOOLEANO)	tipot = "int32";            			       			
            	}
	)?
	ID
	{
		// Si existe un simbolo con el mismo nombre y es un campo
		if (tActiva.existeSimbolo($ID.text)){
			if ( tActiva.busca($ID.text).esCampo())
			{
				ErrorSem1($ID.line,$ID.pos,$ID.text);	//Error 1 (fila,columna): 'lexema' ya existe en este ambito
			}
				
		}
		if (tActiva.obtenPadre().getNombre()==$ID.text && ambito=="metodo")
		{
			ErrorSem31($ID.line,$ID.pos);	// Un constructor no puede devolver nada 
		}
		if (tActiva.obtenPadre().getNombre()!=$ID.text && ambito=="constructor")
		{
			ErrorSem32($ID.line,$ID.pos);	// un metodo debe devolver algo
		}		
		if(ambito=="constructor")
		{			
			$eixida+=".method public specialname rtspecialname instance void .ctor (";
			devuelveTipo = Simbolo.CONSTRUCTOR;
		}
		else
		{
			$eixida+=".method public "+tipot+" '"+$ID.text+"' (";
		}
	}
	PARI
	args
	{
		// si existe ya el metodo con el mismo numero de argumentos
		if(tActiva.sacaMetodo($ID.text,$args.numArgs)!=null)
		{				
			meth=simbaux.getClasse()+"."+$ID.text+"("+$args.argStrin+")";
			ErrorSem20($ID.line,$ID.pos,meth); // El metodo ya esta definido
		}
		else
		if (ambito=="constructor")
		{
			if ($args.argStrin=="")
			{
				// indico que ha encontrado el constructor por defecto
				tActiva.obtenPadre().encontroCtorPorDefecto=true;
			}
			// si existe y num distinto de args, es un sobrecargado			
		}		
		$eixida+=$args.argStrin;
	}
	PARD
	{
		$eixida+=") cil managed\n{\n";
		
		simbaux= new Simbolo($ID.text,Simbolo.METODO,devuelveTipo,0);
		for (int ii=0;ii<$args.argums.size();ii++)
		{
			simbaux.anyadeArgumento((Simbolo)$args.argums.get(ii));
		}
		tActiva.meteMetodoAcabado(simbaux);
		tActiva = tActiva.tPadre.busca($ID.text).getTablaSimbolos();		
	}	
	bloque[ambito]{
		
		if ($bloque.loca_les.length()>0)
		{
			fritanga = $bloque.loca_les.substring(0,$bloque.loca_les.length()-2);
		}
		$eixida+=".maxstack " +($bloque.maxPila+15)+"\n" ;
		$eixida+=".locals(" + fritanga + ")\n" ;
		$eixida+= $bloque.eixida;
		
		if(ambito=="metodo" && tActiva.obtenPadre().requiereRet())
		{
			if (tActiva.obtenPadre().getRetorno() == Simbolo.REAL) 	  
			{ $eixida +="ldc.r8 0\n";}			
			else 					
			{$eixida +="ldc.i4 0\n";}
		}
		$eixida +="ret\n}\n";
		
		tActiva = tActiva.pop();
	}
	|
	PUBLIC
	STATIC
	VOID
	MAIN
	{
		estaEnMain = true;
		if (!mainTrobat)	{mainTrobat=true;}
		else		{ErrorSem18();}	//Error 18: debe existir un unico metodo Main
		
		tActiva.meteMetodoAcabado(new Simbolo("main",Simbolo.METODO,Simbolo.MAIN,0));
		tActiva = tActiva.tPadre.busca("main").getTablaSimbolos();
	}
	PARI
	PARD
	bloque["main"]
	{
		if ($bloque.loca_les.length()>0)
		{
			fritanga = $bloque.loca_les.substring(0,$bloque.loca_les.length()-2);
		}
		$eixida+=".method static public void main () cil managed\n{\n.entrypoint\n.maxstack " +
		($bloque.maxPila+15) +"\n.locals(" + fritanga + ")\n" + $bloque.eixida +"ret\n}\n";

		tActiva = tActiva.pop();
		estaEnMain = false;
		
	}
	;

args returns [String argStrin,int numArgs, ArrayList argums]
	@init{
		$argStrin= "";
		$numArgs=0;
		$argums=new ArrayList();
	}:
	(
	DOUBLE
	id1=ID
	{
		$numArgs++;
		$argStrin+="double";
		$argums.add(new Simbolo($id1.text,Simbolo.VAR,Simbolo.REAL,0));
	}
	(
	COMA
	DOUBLE
	id2=ID
	{
		$numArgs++;
		$argStrin+=",double";
		$argums.add(new Simbolo($id2.text,Simbolo.VAR,Simbolo.REAL,0));
	}	
	)*
	)?
	;

tipo returns [String eixida, String tipoStrin, int tipet]
	@init{
		$eixida= "";
		$tipoStrin="";
		$tipet=0;
		
	}:
	ID
	{
		// del tipo de una clase
		$tipoStrin = $ID.text;
		$tipet = Simbolo.ESPECIAL;
	}
	|
	tiposimple
	{
		$tipet=$tiposimple.tipo;
		$tipoStrin=$tiposimple.tipoStrin;	
	}
	;

tiposimple returns [String eixida, int  tipet, int tipo, String tipoStrin, int linea, int posicion] // linea y posicion los usamos en new TipoSimple
	@init{
		$eixida= "";
	}:
	INT{
		$tipet = Simbolo.ENTERO;
		$linea = $INT.line;
		$posicion = $INT.pos;
		$tipoStrin=$INT.text;
		$eixida+= $tipoStrin;
	}
	| DOUBLE{
		$tipet = Simbolo.REAL;
		$linea = $DOUBLE.line;
		$posicion = $DOUBLE.pos;
		$tipoStrin=$DOUBLE.text;
		$eixida+= $tipoStrin;
	}
	| BOOL{
		$tipet = Simbolo.BOOLEANO;
		$linea = $BOOL.line;
		$posicion = $BOOL.pos;
		$tipoStrin=$BOOL.text;
		$eixida+= $tipoStrin;
	}{
	
	$tipo= $tipet;
	
	};

decl[String visibilitat] returns [String eixida, int maxPila, String loca_les]
	@init{
		$eixida= "";
		$maxPila = 0;
		$loca_les="";
	}:
	tipo
	// tipet es aquello de SIMBOLO.ENTERO
	// tipoStrin es el string con la cadena del tipo
	v1= varid [$tipo.tipoStrin,$tipo.tipet,$visibilitat]{
		$eixida+= $v1.eixida;
		$maxPila = Math.max($maxPila, $v1.maxPila);
		$loca_les+=v1.loca_les;
	}

	(
	COMA
	v2= varid [$tipo.tipoStrin,$tipo.tipet,$visibilitat]{
		$eixida += $v2.eixida;
		$maxPila = Math.max($maxPila, $v2.maxPila);
		$loca_les+=v2.loca_les;
	}
	)*
	PYC
	;
varid [String tipoStrin,int tipo,String visibilitat] returns [String eixida, int maxPila, String loca_les]
	@init{
		int contElementos=0;
		$eixida= "";
		$maxPila=0;
		String cocobongo="";
		String loca_les="";
		int pos=0;
		int tipoSim = Simbolo.VAR; 
		
	}:
	ID{
		if(tActiva.existeSimbolo($ID.text)){
		
			ErrorSem1($ID.line,$ID.pos,$ID.text);	//Error 1 (fila,columna): 'lexema' ya existe en este ambito
			
		}
		if 	( $tipo==Simbolo.ENTERO)  	cocobongo += "int32";
		else if ( $tipo==Simbolo.REAL) 		cocobongo += "float64";
		else if ( $tipo==Simbolo.BOOLEANO)	cocobongo += "int32";
		else if ( $tipo==Simbolo.ESPECIAL)	
						{	cocobongo +="'"+$tipoStrin+"'";
							tipoSim = Simbolo.OBJETO;
						}
	}
	(CORI
	{// Registramos que es un vector
		if ($tipo ==Simbolo.ESPECIAL)
		{
			ErrorSem25($CORI.line,$CORI.pos);// no se permite la declaracion de arrays de objetos
		}
		contElementos++;
	}
	(COMA
	{
	// cantidadElementos++
		contElementos++;
	}
	)*
	CORD
	{
		cocobongo += " []";
		$maxPila = 1;
	}
	)?
	{
		// variable de bloque
		if ($visibilitat=="")
		{
			if ($tipo==Simbolo.ESPECIAL)
			{
				loca_les+="class ";
			}			
			loca_les += cocobongo + ", ";
			pos = posicionSimbolo++;
		}
		else
		{
			// campo de clase
			$eixida=".field "+$visibilitat+" "+cocobongo+" '"+$ID.text+"'";
		}
		
		// Como le pasamos la tabla de clase o de metodo dependiendo de quien la llame,
		// no nos preocupamos aqui de si es un campo o una variable		
		tActiva.nuevoSimbolo($ID.text,tipoSim,$tipo,pos,contElementos);
		if ($visibilitat!="")
		{
			if ($visibilitat == "public")
			{
				tActiva.busca($ID.text).setPublico();
			}
			else
			{
				tActiva.busca($ID.text).setPrivado();
			}
		}

	}
	;

instr[int saltoinicio, int saltofinal, String ambito] returns [String eixida, boolean vieneDeBreakOContinue, int maxPila, String loca_les]
	@init{
		//bool conElse = false;
		//bool conSigno= false;

		boolean conElse = false;
		boolean conSigno= false;
                		boolean metodo= false;
                boolean privado= false;
		int indice= 0;
		int tipo=0;
		int saltaux=0;
		int saltaux2=0;
		int saltaux3=0;
		Simbolo simbaux= null;
		String auxStrin="";
               	Simbolo simbaux2= null;
                ArrayList<Integer> sim1 = new ArrayList<Integer>();
                ArrayList<Simbolo> sim2 = new ArrayList<Simbolo>();
		$eixida="";
		$vieneDeBreakOContinue= false;
		$maxPila=0;
		$loca_les="";

	}:
	bloque[ambito] {
		$eixida += $bloque.eixida;
		$maxPila = $bloque.maxPila;
		$loca_les=$bloque.loca_les;
		tActiva = tActiva.pop();
		
	}
	|
	IF PARI
	expr{
		$eixida += $expr.eixida;
		$eixida += "ldc.i4 0\n";
		$eixida += "bne.un L" + contSalto +"\n";
		$eixida += "br L" + (contSalto+1) +"\n";
		saltaux= contSalto;
		contSalto+=3;

		$maxPila = Math.max($expr.maxPila, 3);
	}
	PARD
	i1= instr[0,0,ambito]
	{
		$eixida +="L" + saltaux +":\n";
		$eixida +=$i1.eixida;
		$eixida +="br L" + (saltaux+2)+"\n";
		$maxPila = Math.max($maxPila, $i1.maxPila);
		$loca_les=$i1.loca_les;
	}
	(ELSE i2=instr[0,0,ambito]{
	 	conElse= true;
		$eixida +="L" + (saltaux+1) +":\n";
		$eixida += $i2.eixida;
		$loca_les=i2.loca_les;
	}
	)?{
		if(!conElse)
		{
			$eixida +="L" + (saltaux+1) +":\n";
			$maxPila = Math.max($maxPila, $i2.maxPila);
		}
		$eixida += "L" + (saltaux+2) +":\n";
	}

	|

	WHILE PARI
	{
		saltaux= contSalto;
		$eixida += "L"+ contSalto++ + ":\n";
	}
	expr
	{
		if($expr.tipo!=Simbolo.BOOLEANO)
		{
			ErrorSem5($WHILE.line,$WHILE.pos,"while");
		}
		$eixida += $expr.eixida;  //adimos el cod de la condici, que deja un 1 o un 0 en la pila
		$eixida += "ldc.i4 0\n";	// apilamos 0 para comparar
		$eixida += "bne.un L"+ (contSalto+1) + "\n";	// si no son iguales, al codigo de la instruccion
		$eixida += "br L"+ (contSalto+2) + "\n";	// iguales, salgo del bucle
		saltaux2= contSalto;
		contSalto+=3;

		$maxPila = Math.max(3, $expr.maxPila);
	}
	PARD
	i3= instr[saltaux,saltaux2+2,ambito]
	{
		saltaux3= contSalto;
		contSalto= saltaux2;
		$eixida += "L"+ (contSalto+1) + ":\n";
		$eixida += $i3.eixida;
		$eixida += "br L"+ saltaux + "\n";
		$eixida += "L"+ (contSalto+2)  +":\n";
		contSalto = saltaux3;

		$maxPila = Math.max($maxPila, $i3.maxPila);
		$loca_les=i3.loca_les;
	}
	|
	FOREACH PARI{
		tActiva = new TablaSimbolos(tActiva); // para estas tablas ins, obtenPadre()==null
	} VAR id1 = ID
	{
		// ponemos a 0 porque es el indice que recorre el vector
		tActiva.nuevoSimbolo($id1.text,Simbolo.VAR,Simbolo.ENTERO,posicionSimbolo++,true);
		$loca_les += "int32, ";
		$eixida += "ldc.i4 0\n";
		$eixida += "stloc " + (posicionSimbolo-1) +"\n"; // inicializo var a 0
		saltaux = contSalto++;
		$eixida += "L"+ saltaux +":\n";  // etiqueta para el comienzo del bucle

		$maxPila = 3;

	} IN
	subref
	{
		simbaux = tActiva.busca($subref.eixida);
           	if(simbaux == null){
           		ErrorSem2($subref.lin,$subref.pos,$subref.eixida); // no ha sido declarado
           	}

          	$eixida += "ldc.i4 "+ String.valueOf(simbaux.obtenDimensionTotal()) +"\n"; // devuelve el tamanyo del vector
           	$eixida += "ldloc " + (posicionSimbolo-1) +"\n";		// en la pila el indice
           	saltaux2 = contSalto++;
           	$eixida += "bgt L"+ saltaux2 +"\n"; // Si el tope el mayor que el indice, salta a la instr
           	saltaux3 = contSalto++;
           	$eixida += "br L"+ saltaux3 +"\n"; // si no, salimos del bucle

           	$maxPila = Math.max ($maxPila, 4);

	} PARD
	i4=instr[saltaux,saltaux3,ambito]{
		$eixida += "L"+ saltaux2 +":\n";
		$eixida += $i4.eixida;

		// Actualizamos el indice
		$eixida += "ldloc " + (posicionSimbolo-1) +"\n";
		$eixida += "ldc.i4 "+ String.valueOf(simbaux.obtenDimensionTotal())+"\n";
		$eixida+="add\n";
		$eixida+= "stloc " + (posicionSimbolo-1) +"\n";
		$eixida+= "br L" + (saltaux) +"\n";
		// Salida del bucle
		$eixida+= "L" + saltaux3 +":\n";
		//emitErrorMessage("CATAPLASMA");
		simbaux.quitaIndice();
		tActiva = tActiva.pop();
		
		$maxPila = Math.max ($maxPila, $i4.maxPila);
		$loca_les+=i4.loca_les;
	}

	|
	FOR PARI{

		tActiva = new TablaSimbolos(tActiva);
		$loca_les += "int32, ";
	}
	 INT ID ASIG
	e1=expr{
			tActiva.nuevoSimbolo($ID.text,Simbolo.VAR,Simbolo.ENTERO,posicionSimbolo++,true);
			$eixida += $e1.eixida;
			$eixida += "stloc " + (posicionSimbolo-1) +"\n";
			$maxPila = $e1.maxPila;

	}
	TO
	e2=expr{
		//emitErrorMessage(((Integer)Simbolo.ENTERO).toString() + " " + ((Integer)e2.tipo).toString());


		if($e2.tipo!=Simbolo.ENTERO && $e2.tipo!=Simbolo.REAL){
			ErrorSem17($TO.line,$TO.pos,$TO.text); 
			//  Error 17 (fila,columna): la expresion debe ser de tipo numerico
		}
		$eixida += $e2.eixida;
		//En teoria, en cada iteraciob el resultado de la expresion aparecera antes de la comparacion
		//en la cima de la pila. Si esto no funcionara, tendremos que almacenarlo en una variable
		//y cargarlo justo cuando cargamos el valor del simbolo indice.
		saltaux = contSalto;
		$eixida += "L"+ contSalto++ + ":\n";
		$eixida += "ldloc " + (posicionSimbolo-1) +"\n";

	}
	STEP (ADDOP{conSigno= true;})? ENTERO PARD{
		saltaux2= contSalto;
		if(conSigno && $ADDOP.text.equals("-")){
			$eixida += "ble L"+ contSalto++ +"\n";
		} else {
			$eixida += "bge L"+ contSalto++ +"\n";
		}
		$eixida += "br L" + contSalto++ +"\n";
		$maxPila = Math.max ($maxPila, $e2.maxPila+3);
	}
	i5=instr[saltaux,saltaux2+1,ambito]{

		$eixida += "L" + (saltaux2) +":\n";
		$eixida += $i5.eixida;
		$eixida += "ldloc " + (posicionSimbolo-1) +"\n";
		$eixida += "ldc.i4 "+ $ENTERO.text+"\n";
		if(conSigno && $ADDOP.text.equals("-")){
			$eixida+="sub\n";
		} else {
			$eixida+="add\n";
		}
		$eixida+= "stloc " + (posicionSimbolo-1) +"\n";
		$eixida+= "br L" + (saltaux) +"\n";
		$eixida+= "L" + (saltaux2+1) +":\n";
		tActiva = tActiva.pop();
		
		$maxPila = Math.max ($maxPila, $i5.maxPila);
		$loca_les+=i5.loca_les;
	}

	|

	BREAK PYC{
		if($saltoinicio==0&&$saltofinal==0){
			ErrorSem16($BREAK.line,$BREAK.pos+1,$BREAK.text);//Error 16 (fila,columna): instruccion 'lexema' no permitida fuera de un bucle
		}
		$eixida+= "br L"+saltofinal+"\n";
	}
	|

	CONTINUE PYC{
		if($saltoinicio==0&&$saltofinal==0){
			ErrorSem16($CONTINUE.line,$CONTINUE.pos+1,$CONTINUE.text);//Error 16 (fila,columna): instruccion 'lexema' no permitida fuera de un bucle;
		}
		$eixida+= "br L"+saltoinicio+"\n";
	}
	|
	ref
	{
	 // OJO OJO   Esta accion se puede llevar a cabo tanto sobre 
		// variables locales ldloc... como sobre los campos de una clase en un constructor
		// por ejemplo, en tal caso, seria algo como ldarg 
		//completar mas

		if($ref.vector)
		{
			$eixida+="ldloc "+$ref.eixida;

			// quedando
			// ldloc [posicion del array en locals]
			// ldl.i4 [posicion del elemento dentro del array]
			$maxPila = 1;
		}
	}
	cambio[$ref.tipo,$ref.esindice,$ref.cadClase]	// dentro de cambio se comprueba el tipo
	{
		// Esto es lo que ha puesto Angel
		$eixida +=$cambio.eixida;
		if(!$ref.vector)
		{
			$eixida += "stloc "+ $ref.eixida + "\n";
		}
		else
		{
			if($ref.tipo == Simbolo.REAL )		
				{$eixida += "stelem.r8\n";	}// Si lo que se devuelve en "cambio" es un real, hay que convertirlo
			else if($ref.tipo == Simbolo.ENTERO )	
				{$eixida += "stelem.i4\n";	}			
		}
		$maxPila = 4;
	}
	|
	ID
	{
		simbaux = tActiva.busca($ID.text);
		if(simbaux == null){
           		ErrorSem2($ID.line,$ID.pos,$ID.text); // no ha sido declarado
           	} else {
           		if(!simbaux.esArray())
           		{
           			ErrorSem11($ID.line,$ID.pos+1,$ID.text); // no es un array
           		}
           		tipo =simbaux.tipo;
           	}
	}
	ASIG NEW
	tiposimple
	{
		if (tipo != $tiposimple.tipo)
		{
			ErrorSem14($tiposimple.linea,$tiposimple.posicion+1,$tiposimple.eixida); // no es el tiposimple que corresponde
		}
	}
	CORI
	dims[simbaux]
	CORD
	{
		if (!simbaux.setOrra($dims.tamanyos))	// insertamos las dimensiones en el simbolo
		{
                    ErrorSem10($CORD.line,$CORD.pos+1,$CORD.text);// faltan dimensiones
		}
		// generar
		// ldc.i4 $dims.dimensionTotal
		// newarr[mscorlib] System. [Double/int32]
		// stloc simbaux.getPosicion()
		$eixida += "ldc.i4 "+ $dims.dimensionTotal + "\n";
		$eixida += "newarr[mscorlib] System.";
		if (tipo == Simbolo.REAL)
		{
			$eixida +="Double\n";
		}else
		{
			$eixida +="Int32\n";
		}
		$eixida += "stloc "+ String.valueOf(simbaux.getPosicion())+"\n";
		$maxPila = 4;
	}
	PYC
	|

	WRITELINE PARI
	expr {
		$eixida+= $expr.eixida;
		$eixida += "call void [mscorlib]System.Console::WriteLine(";
		if($expr.tipo==(Simbolo.ENTERO)) $eixida+= "int32)\n";
		else if($expr.tipo==(Simbolo.REAL)) $eixida+= "float64)\n";
		else if($expr.tipo==(Simbolo.BOOLEANO)) $eixida+="bool)\n";
		else if($expr.tipo==Simbolo.ESPECIAL)
		{
		                    ErrorSem28($WRITELINE.line,$WRITELINE.pos,$WRITELINE.text);
		                    // la referencia es de tipo incorrecto
		}
		$maxPila = $expr.maxPila+1;
	}
	PARD PYC
	|
	RETURN
	{
		if($ambito=="main" || ambito=="constructor")
		{
			ErrorSem22 ($RETURN.line,$RETURN.pos+1); 
		}
		//No tenemos que incluir el retorno por defecto porque ya se lo ponemos aqui 
		tActiva.obtenPadre().setRequiereRetorno(false);
	}
	expr
	{
		$eixida+=$expr.eixida;
		
		// Si tiene que devolver algo de otro tipo, se convierte
		if($expr.tipo!=tActiva.obtenPadre().getRetorno())
		{
			if (	$expr.tipo==Simbolo.ESPECIAL ||
				$expr.tipo==Simbolo.BOOLEANO && tActiva.obtenPadre().getRetorno()!=Simbolo.BOOLEANO ||
				$expr.tipo!=Simbolo.BOOLEANO && tActiva.obtenPadre().getRetorno()!=Simbolo.BOOLEANO)
			{
				ErrorSem23($RETURN.line,$RETURN.pos+1); 
			}
			else
			if (tActiva.obtenPadre().getRetorno()==Simbolo.ENTERO)
			{
				$eixida += $expr.eixida + "conv.i4\n";
			}
			else
			{
				$eixida += $expr.eixida + "conv.r8\n";
			}
		}
		
	}
	PYC
	|
	// A a; a=new A();
	a=ID{
            simbaux = tActiva.busca($a.text);
            if(!tActiva.existeSimbolo($a.text)){
                 ErrorSem2($a.line,$a.pos,$a.text); // No ha sido declarado
            }
            if(!simbaux.esObjeto()){
                ErrorSem19($a.line,$a.pos,$a.text) ;//  identificador usado incorrectamente (no es objeto)
            }
        }
	ASIG NEW
	b=ID {
            if(!TablaSimbolos.existeClase($b.text)){
                ErrorSem2($b.line,$b.pos,$b.text); // No ha sido declarado
            }
            if(TablaSimbolos.obtenClase($a.text).equals($b.text)){
                ErrorSem26($a.line,$a.pos,$a.text,$b.text); //objeto tal no es de la clase cual
            }
        }
	PARI	
	params
	{
                simbaux2 = tActiva.sacaMetodo($b.text,$params.numArgs);
                if(simbaux2.getTablaSimbolos().existeMetodo($b.text,$params.numArgs))
                {
                                simbaux2 = simbaux2.getTablaSimbolos().sacaMetodo($b.text,$params.numArgs);
                }
                else
                {	 			
                                ErrorSem21($b.line,$b.pos,$b.text+"."+$b.text+""+"ponia DolarinParamsPuntoArgs y no compila, asi que, arco del triunfo"+"");
                                //El metodo met no esta definido
                }
           	$eixida+=$params.eixida;
                $eixida+= "newobj instance void '"+ simbaux2.getNombre()+"'::.ctor(" + $params.tiposCil+ ")\n";
            	if(simbaux2.tPadre.obtenPadre().esCLASE()){
              		$eixida+= "ldarg.0\n";
                	$eixida+= "stfld object " + simbaux2.getNombre() + "'::'" + simbaux.getNombre()+"'\n";
                }
            	else {
                	$eixida+="stloc " + simbaux.getPosicion() +"\n";
            	}
        }
	PARD
	PYC
	|
	subref
	{
            		$eixida+= $subref.eixida;
           		 tipo = $subref.tipo;           
        }
	PARI
	params{
             	$eixida+= $params.eixida;
       		simbaux= TablaSimbolos.obtenClase($subref.cadClase);
             	simbaux= simbaux.getTablaSimbolos().sacaMetodo($subref.cadMetodo,$params.numArgs);
                if(!simbaux.getTablaSimbolos().existeMetodo($subref.cadMetodo,$params.numArgs)){
                     ErrorSem21(auxHashingName1,auxHashingName2,$subref.cadClase+"."+$subref.cadMetodo+"("+$params.tiposFuente+")");
                }
            	if(simbaux.esConstructor()){
			ErrorSem30($subref.pos, $subref.lin);
             	}  
                $eixida+= "call instance " +"void"+ " '"+$subref.cadClase+"'::'"+$subref.cadMetodo+"'(" + $params.tiposCil + ")\n";
        }
	PARD
	;



bloque[String ambito] returns [String eixida, int tampila, int maxPila, String loca_les]
	@init{
		$eixida = "";
		$loca_les="";
	}:
	LLAVEI
	{
	// cuando bloque es llamado como una intruccion intr -> bloque
		if ( tActiva.obtenPadre()==null)
		{
			tActiva = new TablaSimbolos(tActiva);
		}
	}
	declins[ambito] {
		$eixida += $declins.eixida;
		$maxPila = $declins.maxPila;
		$loca_les += $declins.loca_les;
	}
	LLAVED 
	;

declins[String ambito]  returns [String eixida, int maxPila, String loca_les]
	@init{
		$eixida= "";
		$maxPila = 0;
		$loca_les="";
	}:
	(
	instr[0,0,ambito]{
		$eixida += $instr.eixida;
		$maxPila = Math.max($maxPila, $instr.maxPila);
		$loca_les+=$instr.loca_les;
	}
	|
	decl[""]{
		$eixida += $decl.eixida;
		$maxPila = Math.max($maxPila, $decl.maxPila);
		$loca_les+=$decl.loca_les;
	}
	)*
	;

dims[Simbolo sim] returns [String eixida, ArrayList tamanyos, int dimensionTotal]
	@init
	{

		int tamanyoDim=0; //  tamanyo de cada dimension
		int cont =0; // dimensiones que vamos anyadiendo
		int tamArray=sim.getTamanyoArray();
	}:
	{
		$eixida="";
	}
	e1=ENTERO
	{
		$tamanyos = new ArrayList();

		tamanyoDim = Integer.parseInt($e1.text);
		if (tamanyoDim <= 0)
		{
			ErrorSem8($e1.line,$e1.pos,$e1.text);// la dimension no es mayor que 0
		}
		$tamanyos.add(tamanyoDim);
		cont++;
		$dimensionTotal = tamanyoDim;
	}
	(COMA e2=ENTERO
	{
		tamanyoDim = Integer.parseInt($e2.text);
		$dimensionTotal = $dimensionTotal * tamanyoDim;
		if (cont >= tamArray) // nos hemos pasado con las dimensiones
		{
			ErrorSem10($COMA.line,$COMA.pos+1,$COMA.text);//Error 10 (fila,columna): numero de dimensiones incorrecto
		}
		if (tamanyoDim <= 0)
		{
			ErrorSem8($e2.line,$e2.pos,$e2.text);//Error 8 (fila,columna): tamanyo incorrecto
		}
		$tamanyos.add(tamanyoDim);
		cont++;

	})*
	;


cambio[int tipo,boolean esindice, String claseOrigen] returns [String eixida]
	@init{
		$eixida= "";
	}:
	ASIG{

		if($esindice){
			ErrorSem15($ASIG.line,$ASIG.pos+1,"He bebido mas cerveza, he meado mas sangre, he echado mas polvos y he chafado mas huevos que todos vosotros juntos, capullos.");
		//Error 15 (fila,columna): la variable que se intenta modificar es una variable indice
		}
	}
	expr{
		if(	
			$tipo!=$expr.tipo && ($tipo==(Simbolo.BOOLEANO) || $expr.tipo==(Simbolo.BOOLEANO)) 
			||
			($tipo==Simbolo.ESPECIAL && $expr.cadClase !=$claseOrigen)
		)
		{
			ErrorSem6($ASIG.line,$ASIG.pos,$ASIG.text);//Error 6 (fila,columna): tipos incompatibles en la instruccion de asignacion
		}
	}
	PYC {

		if($tipo==(Simbolo.REAL) && $expr.tipo==(Simbolo.ENTERO))
		{
			$eixida += $expr.eixida + "conv.r8\n";

		} else if ($tipo==(Simbolo.ENTERO) && $expr.tipo==(Simbolo.REAL)){
			$eixida += $expr.eixida + "conv.i4\n";

		} else {
			$eixida += $expr.eixida;
		}
	}
	|
	PUNTO READLINE{
		if($esindice){
			ErrorSem15($READLINE.line,$READLINE.pos+1,"Tengo tres piscinas");
			//Error 15 (fila,columna): la variable que se intenta modificar es una variable indice
		}
		} PYC{
                if($tipo==Simbolo.ESPECIAL){
                    ErrorSem28($READLINE.line,$READLINE.pos,$READLINE.text);
                }
		$eixida += "call string [mscorlib]System.Console::ReadLine()\n";
		if($READLINE.text.contains("int")){
			if($tipo!=Simbolo.ENTERO) {
				ErrorSem7($READLINE.line,$READLINE.pos,$READLINE.text);
				//Error 7 (fila,columna): tipos incompatibles en la instruccion de lectura
			} else {
				$eixida += "call int32 [mscorlib]System.Int32::Parse(string)\n";
			}
		} else if($READLINE.text.contains("double")){
			if($tipo!=Simbolo.REAL) {
				ErrorSem7($READLINE.line,$READLINE.pos,$READLINE.text);
				//Error 7 (fila,columna): tipos incompatibles en la instruccion de lectura
			} else {
				$eixida += "call float64 [mscorlib]System.Double::Parse(string)\n";
			}
		} else if($READLINE.text.contains("bool")){
			if($tipo!=Simbolo.BOOLEANO) {
				ErrorSem7($READLINE.line,$READLINE.pos,$READLINE.text);
				//Error 7 (fila,columna): tipos incompatibles en la instruccion de lectura
			} else {
				$eixida += "call bool [mscorlib]System.Boolean::Parse(string)\n";
			}
		}

	}
	;

expr returns [String eixida, int tipo, boolean signo, int maxPila]
	@init{
		boolean signo2;
		int tipo2;
		String eixida2;
		$eixida="";
	}:
        ea1=eand{
		$signo = $ea1.signo;
		$tipo = $ea1.tipo;
		$eixida += $ea1.eixida;
		$maxPila=$ea1.maxPila;
        }
        (OR
        ea2= eand {
		signo2 = $ea2.signo;
		tipo2 = $ea2.tipo;
		eixida2 = $ea2.eixida;

		if($tipo!=Simbolo.BOOLEANO || tipo2!=Simbolo.BOOLEANO)
		{
			ErrorSem4($OR.line,$OR.pos,$OR.text);//Error 4 (fila,columna): tipo incompatible en operador logico 'lexema'
		}
		$eixida += eixida2;
		$eixida += "or\n";
		$maxPila=Math.max($maxPila,$ea2.maxPila+1);
        }
        )*
    ;

eand returns [String eixida, boolean signo, int tipo, int maxPila]
	@init{
		boolean signo2;
		int tipo2;
		String eixida2;
		$eixida ="";
	}:
        e1=erel{
		$signo = $e1.signo;
		$tipo = $e1.tipo;
		$eixida += $e1.eixida;
		$maxPila=$e1.maxPila;
        }
        (AND
        e2= erel {
		signo2 = $e2.signo;
		tipo2 = $e2.tipo;
		eixida2 = $e2.eixida;
		if($tipo!=Simbolo.BOOLEANO || tipo2!=Simbolo.BOOLEANO)
		{
			ErrorSem4($AND.line,$AND.pos,$AND.text);//Error 4 (fila,columna): tipo incompatible en operador logico 'lexema'
		}
		$eixida += eixida2;
		$eixida += "and\n";
		$maxPila=Math.max($maxPila,$e2.maxPila+1);
        }
        )*
    ;
erel returns [String eixida, boolean signo, int tipo, int maxPila]
	@init{
		boolean signo2;
		int tipo2;
		String eixida2;
		$eixida ="";
	}:
        e1=esum{
		$signo = $e1.signo;
		$tipo = $e1.tipo;
		$eixida += $e1.eixida;
		$maxPila = $e1.maxPila;
        }
        (RELOP
        e2=esum {
		signo2 = $e2.signo;
		tipo2 = $e2.tipo;
                if($e1.tipo== Simbolo.ESPECIAL || $e2.tipo == Simbolo.ESPECIAL){
                    ErrorSem29($RELOP.line,$RELOP.pos,$RELOP.text);
                }
		eixida2 = $e2.eixida;
		if($tipo==(Simbolo.REAL) && (tipo2==(Simbolo.ENTERO) || tipo2==(Simbolo.BOOLEANO)))
		{
			eixida2 += "conv.r8\n";

		} else if (($tipo==(Simbolo.ENTERO) || $tipo==(Simbolo.BOOLEANO)) && tipo2==(Simbolo.REAL)){
			$eixida += "conv.r8\n";
		}
		$eixida += eixida2;
		$tipo=Simbolo.BOOLEANO;
		if($RELOP.text.equals("==")){
			$eixida += "beq ";
		} else if($RELOP.text.equals("!=")){
			$eixida += "bne.un ";
		} else if($RELOP.text.equals("<")){
			$eixida += "blt ";
		} else if($RELOP.text.equals(">")){
			$eixida += "bgt ";
		} else if($RELOP.text.equals("<=")){
			$eixida += "ble ";
		} else {
			$eixida += "bge ";
		} $eixida += "L" + contSalto++ +"\n";
		$eixida +="ldc.i4 0\nbr L" + contSalto-- + "\nL"+ contSalto++ + ":\nldc.i4 1\nL"+contSalto++ +":\n";

		$maxPila=Math.max($maxPila,$e2.maxPila+1);
        }
        )*
    ;

esum    returns [boolean signo, int tipo, String eixida, int maxPila]
	@init{

		boolean signo2;
		int tipo2;
		String eixida2;
		$eixida ="";
		$signo= true;
	}:
        costra=term{
		$signo = $costra.signo;
		$tipo = $costra.tipo;
		$eixida += $costra.eixida;
		$maxPila = $costra.maxPila;

        }
        (ADDOP
        seca=term {
        	if($tipo==(Simbolo.BOOLEANO) || $tipo==(Simbolo.ESPECIAL)){
			ErrorSem3($ADDOP.line,$ADDOP.pos,$ADDOP.text);//Error 3 (fila,columna): tipo incompatible en operador aritmetico 'lexema'
		}
		signo2 = $seca.signo;
		tipo2 = $seca.tipo;
		eixida2 = $seca.eixida;
		if(tipo2==(Simbolo.BOOLEANO) || $tipo==(Simbolo.ESPECIAL)){
			ErrorSem3($ADDOP.line,$ADDOP.pos,$ADDOP.text);//Error 3 (fila,columna): tipo incompatible en operador aritmetico 'lexema'
		}
		if($tipo==(Simbolo.REAL) && tipo2==(Simbolo.ENTERO))
		{
			eixida2 += "conv.r8\n";

		} else if ($tipo==(Simbolo.ENTERO) && tipo2==(Simbolo.REAL)){
			$eixida += "conv.r8\n";
		}
		$eixida += eixida2;
		if($ADDOP.text.equals("+")){
			$eixida += "add\n";
		} else {
			$eixida += "sub\n";
		}
		$maxPila=Math.max($maxPila,$seca.maxPila+1);
        }
        )*
    ;

term    returns [boolean signo, int tipo, String eixida, int maxPila]
	@init{
		boolean signo2;
		int tipo2;
		String eixida2;
		$eixida="";
	}:
        max=factor{
		$signo = $max.signo;
		$tipo = $max.tipo;
		$eixida += $max.eixida;
		$maxPila = $max.maxPila;
        }
        (MULOP
        pollotriste=factor {
        	if($tipo==(Simbolo.BOOLEANO) || $tipo==(Simbolo.ESPECIAL)){
			ErrorSem3($MULOP.line,$MULOP.pos,$MULOP.text);//Error 3 (fila,columna): tipo incompatible en operador aritmetico 'lexema'
		}
		signo2 = $pollotriste.signo;
		tipo2 = $pollotriste.tipo;
		eixida2 = $pollotriste.eixida;
		if(tipo2==(Simbolo.BOOLEANO) || $tipo==(Simbolo.ESPECIAL)){
			ErrorSem3($MULOP.line,$MULOP.pos,$MULOP.text);// Error 3 (fila,columna): tipo incompatible en operador aritmetico 'lexema'
		}
		if($tipo==(Simbolo.REAL) && tipo2==(Simbolo.ENTERO))
		{
			eixida2 += "conv.r8\n";

		} else if ($tipo==(Simbolo.ENTERO) && tipo2==(Simbolo.REAL)){
			$eixida += "conv.r8\n";
		}
		$eixida += eixida2;
		if($MULOP.text.equals("*")){
			$eixida += "mul\n";
		} else {
			$eixida += "div\n";
		}
		$maxPila=Math.max($maxPila,$pollotriste.maxPila);
        }
        )*
    ;

factor   returns [boolean signo, int tipo, String eixida, int maxPila]
	@init{
		$eixida= "";
		$maxPila=1;
	}:
        base{
		$signo = $base.signo;
		$tipo = $base.tipo;
		$eixida += $base.eixida;
		$maxPila = $base.maxPila;
        }
    	| ouiea=NOT 
    	  xopo=factor{
    		$signo = $xopo.signo;
    		$tipo = $xopo.tipo;
    		$eixida += $xopo.eixida;
    		if($tipo!=Simbolo.BOOLEANO)
    		{
    			ErrorSem4($ouiea.line,$ouiea.pos,$ouiea.text);// Error 4 (fila,columna): tipo incompatible en operador logico 'lexema'
    		} else {
    			$signo = !$signo;
    			$eixida += "not\n";
    		}
    		$maxPila = $xopo.maxPila;
        }
        | PARI adios=ADDOP loco=factor{
            	$signo = $loco.signo;
    		$tipo = $loco.tipo;
    		$eixida += $loco.eixida;
    		if($tipo==(Simbolo.BOOLEANO))
    		{
    			ErrorSem3($adios.line,$adios.pos,$adios.text);//Error 3 (fila,columna): tipo incompatible en operador aritmetico 'lexema'
    		} else {
    			$signo = !$signo;
    			$eixida+="neg\n";
    		}
    		$maxPila = $loco.maxPila;
        }
        PARD
    ;

base    returns [boolean signo, int tipo, String eixida, int maxPila]
	@init{
		$eixida= "";

		$signo = true;
                ArrayList<Simbolo> sim2= new ArrayList<Simbolo>();
                ArrayList<Integer> sim1= new ArrayList<Integer>();
                Simbolo simbaux,simbauxc;
                String meth="";
	}:
         ENTERO {
         	$eixida += "ldc.i4 "+ $ENTERO.text +"\n";
         	$tipo = Simbolo.ENTERO;
         	$maxPila = 1;
         }
         | REAL {
         	$eixida += "ldc.r8 "+ $REAL.text +"\n";
         	$tipo = Simbolo.REAL;
         	$maxPila = 1;
         }
         | BOOLEANO {
         	if($BOOLEANO.text.equals("True")){
         		$eixida += "ldc.i4.1\n";
         	} else {
         		$eixida += "ldc.i4.0\n";
         	}
         	$tipo = Simbolo.BOOLEANO;
         	$maxPila = 1;

         }

    	| PARI expr{
                auxHashingName1 = $PARI.line;
                auxHashingName2 = $PARI.pos;
    		$eixida += $expr.eixida;
    		$tipo = $expr.tipo;
    		$signo = $expr.signo;
    		$maxPila = $expr.maxPila;
        }
        PARD
	|
	ref
	{
	 	$eixida += "ldloc "+ $ref.eixida;
	 	$tipo = $ref.tipo;
	 	$signo = $ref.signo;

   		if ($ref.vector)
		{
			if($ref.tipo == Simbolo.REAL )
			{
				$eixida += "ldelem.r8\n";
			}
			else
			{
				$eixida += "ldelem.i4\n";
			}
		}
		$maxPila=Math.max(3,$ref.maxPila);
        }
        |
        subref{
            $eixida+= $subref.eixida;
            $tipo = $subref.tipo;

        }
	PARI
	params{
             sim1= $params.tipoParametros;
             simbauxc= TablaSimbolos.obtenClase($subref.cadClase);
             simbaux= simbauxc.getTablaSimbolos().sacaMetodo($subref.cadMetodo,$params.numArgs);
             if(simbaux.esConstructor()){
                ErrorSem30($subref.pos, $subref.lin);
             }
             sim2 = simbaux.argumentos;
             if(sim2!= null && sim2.size()==sim1.size()){
                for(int y=0; y< sim2.size(); y++){
                    if(sim2.get(y).tipo != sim1.get(y)){
                        ErrorSem24($pari.line,$pari.pos,"MATEME, SE LO RUEGO");
                    }
                }
             } else {
             	meth = $subref.cadClase+"."+$subref.cadMetodo+"("+$params.tiposFuente+")";
                ErrorSem21($subref.pos,$subref.lin,meth);
             }
             eixida+= "call instance "  +simbaux.devuelveTipoNazi()+ " '"+$subref.cadClase+"'::'"$subref.cadMetodo"'(" + $params.eixida + ")\n";
        }
	PARD
    ;

// puede ser llamado para lectura (desde Base) o para escritura (desde Instr->ref cambio)
ref returns[String eixida, int tipo, boolean signo, boolean vector, boolean esindice, int maxPila, boolean privado, String cadClase]
	@init{
	Simbolo simbaux= null;
	boolean corchetes = true;
                	boolean esObjeto = false;
	$eixida= "";
	}:
            subref
            {
            	// yo pa mi que a esto le falta un hervor. Ahi lo dejo
                if(TablaSimbolos.existeClase($subref.cadClase)){
                     esObjeto = true;
                     cadClase=$subref.cadClase; // para comprobar en instr-> ref cambio
                }
           	simbaux = tActiva.busca($subref.eixida); 
                privado = simbaux.esPrivado();
           	if(simbaux == null){
           		ErrorSem2($ID.line,$ID.pos,$ID.text);
           		// no ha sido declarado
           	} else {
			if(simbaux.esIndice()) $esindice=true;
           		$eixida += String.valueOf(simbaux.getPosicion()) + "\n"; 
           		$tipo =simbaux.tipo;
           	}
		$maxPila = 1;
           }
          (CORI
           {
                if(simbaux.esObjeto()){
                    ErrorSem24($subref.lin, $subref.pos);
                    // Parametro ha de ser double
                }
           	if(!simbaux.esArray())
           	{
           		ErrorSem11($CORI.line,$CORI.pos+1,$CORI.text);
           	}
           	$vector = true;
           }
           indices[simbaux,$CORI.line,$CORI.pos]
           {
           	$eixida +=$indices.eixida;//+posicion dentro del array
           	$maxPila = Math.max( $indices.maxPila,$maxPila);
           }
           CORD)?
           {
           	if(simbaux.esArray() && (!corchetes || $indices.cont < simbaux.getTamanyoArray() ))
           	{
           		ErrorSem9($CORI.line,$CORI.pos+1,simbaux.getNombre());
           		// Error 9 (fila,columna): numero insuficiente de indices en el array 'lexema'
           	}
           }
                      ;
indices[Simbolo sim, int linea, int columna] returns[String eixida,int cont, int indicesPos, int maxPila, int tipo]
	@init{
		$eixida="";
		$cont = 0;
	}:
	e1 = expr{
		$eixida += "ldc.i4 0\n";// cargo un 0 para la primera suma
		$eixida += $e1.eixida;

        	if ($e1.tipo==Simbolo.REAL)
        	{
        		$eixida += "conv.i4 "+ "\n";
        	}
        	else
        	if ($e1.tipo!=Simbolo.ENTERO)
        	{
        		ErrorSem13(linea,columna);// indice de tipo incompatible
        	}
        	$cont++;
        	$eixida += "ldc.i4 "+ $sim.getDimParcial($cont) +"\n";
        	$eixida += "mul\n";
        	$eixida += "add\n";
		$maxPila = Math.max( $e1.maxPila,3);
        }
        (COMA
        e2 = expr{
        	$eixida += $e2.eixida;
        	if ($e2.tipo==Simbolo.REAL)
        	{
        		$eixida += "conv.i4 "+ "\n";
        		$tipo=Simbolo.ENTERO;
        	}
        	if ($e2.tipo!=Simbolo.ENTERO)
        	{
        		ErrorSem13($COMA.line,$COMA.pos+1);
        		// indice de tipo incompatible
        	}
        	$cont++;
        	if ($cont > $sim.getTamanyoArray()) // hay mas indices de que los que soporta el array
        	{
        	        ErrorSem12($COMA.line,$COMA.pos+1,$COMA.text);
        	        // Error 12 (fila,columna): demasiados indices
        	}

        	$eixida += "ldc.i4 "+ $sim.getDimParcial($cont) +"\n";
        	$eixida += "mul\n";
        	$eixida += "add\n";
        	$maxPila = Math.max( $e2.maxPila,3);
        }
        )*
	;

subref returns [String eixida, String cadClase, String cadMetodo, int tipo,int pos,int lin]
	@init{
		$eixida="";
                $cadClase= "";
                $cadMetodo= "";
                boolean hayPunto= false;
                ArrayList<Integer> ids = new ArrayList<Integer>();
                int caqui=0;
                Simbolo simbaux, sim2 = null;
                Simblolo simbauxClas=null;
                int numArg=0;
	}:
	i1=ID{
            $pos = $i1.pos;
            $lin = $i1.line;
            ids.add($i1.text);
            
            // si idtext esta en la tabla de simbolos, no hay problema, lo encontramos en locals
            if (tActiva.existeSimbolo($i1.text))
            {                        	
            	simbaux = tActiva.buscaSimbolo($i1.text);           
            	eixida+= "ldloc " + simbaux.getPosicion() + "\n"; // carga local         
            }
            else
            {
            	if ((simbaux =tActiva.buscaSimbolo($i1.text))!=null)
            	{
            		if (estaEnMain){	ErrorSem27($i1.line,$i1.pos,$i1.text);// miembro lexema no accesible desde main            			
            		}
            		else
            		{
            			eixida+= "ldarg 0\n";
            			if (!simbaux.esMETODO())
            			{ 
            				$cadClase = simbaux.getNomClasse();//  carga campo         				
            				eixida+= "ldfld "+ simbaux.devuelveTipoNazi() + " '" + $cadClase + "'::'" + simbaux.getNombre()+"'\n";
            				simbauxClas = TablaSimbolos.obtenClase($cadClase);
            			}
            			else
            			{	
            				$cadClase = simbaux.getNomClasse();
            				$cadMetodo = simbaux.getNombre();
            			}
            		}
            	}
            }
            else if (tActiva.obtenPadre().esMETODO() && tActiva.obtenPadre().estaArgumento($i1.text))
            {     	
            	simbaux = tActiva.obtenPadre().getArgumento($i1.text);
            	numArg = tActiva.obtenPadre().getNumArgumento($i1.text) + 1;
            	// carga argumento
            	eixida+= "ldarg " + numArg + "\n";	            	
	    }
	    else       	
	    {
	            ErrorSem2($i1.line,$i1.pos,"Pam");//simbolo 'lexema' no ha sido declarado	            
	    } 
        }
	(
	PUNTO{
            hayPunto = true; // significa que vamos a acceder a un metodo de instancia o a un campo
            if (!simbaux.esObjeto() || simbaux.esMETODO())
            {
	            ErrorSem2($PUNTO.line,$PUNTO.pos,"Pam");//simbolo 'lexema' no ha sido declarado	            
	    } 
        }
	i2 = ID 
	{
            ids.add($i2.text);
            $pos = $i2.pos;
            $lin = $i2.line;
            
            // lo que viene despues del punto es un campo-objeto, un campo-noObjeto o un metodo
            // hay que comprobar la existencia y la privacidad
            // tanto un objeto como un metodo pertenecen a un clase
            
            // si lo que aparece aqui es un metodo 
            if ((sim2=simbauxClas.busca($i2.text))!=null)
            {	
            	if (sim2.esPublico())
            	{
            	        $cadClase = sim2.getNomClasse();
            		if (sim2.esMETODO())
            		{
            			$cadMetodo = sim2.getNombre();
            		}
            		else
            		{
            			if (sim2.esObjeto())
            			{           				
            				simbauxClas = TablaSimbolos.obtenClase($cadClase);            				
            			}
            			eixida+= "ldfld "+ simbaux.devuelveTipoNazi() + " '" + $cadClase + "'::'" + simbaux.getNombre()+"'\n";            				
            		}
            	}
            	else
            	{
            	     ErrorSem2($i2.line,$i2.pos,"Pam");//simbolo 'lexema' no ha sido declarado
           	}
            }
            else
            {
            	ErrorSem2($i2.line,$i2.pos,"Pam");//simbolo 'lexema' no ha sido declarado
            }    
            
        }
	)*
	;

params returns [String eixida, int numArgs, String tiposFuente, String tiposCil, ArrayList<Integer> tipoParametros]
	@init{
		$eixida="";
                $numArgs=0;
                $tiposFuente="";
                $tiposCil="";
	}:
	(
	e1 = expr {
            $numArgs++;
            $tiposFuente+= Simbolo.devuelveTipoCadena($e1.tipo);
            $tiposCil="float64";
            $eixida+= $e1.eixida;
            if($e1.tipo!=Simbolo.REAL){
                if($e1.tipo==Simbolo.ENTERO){
                    $eixida+= "conv.r8\n";
                } else {
                    ErrorSem24(auxHashingName1,auxHashingName2);
		    // Los parametros han de ser reales
                }
            }     
        }
	(
	COMA
	e2 = expr {
            $numArgs++;
            $tiposFuente+= ","+Simbolo.devuelveTipoCadena($e2.tipo);
            $tiposCil+=",float64";
            $eixida+= $e2.eixida;
            if($e2.tipo!=Simbolo.REAL){
                if($e2.tipo==Simbolo.ENTERO){
                    $eixida+= "conv.r8\n";
                } else {
                    ErrorSem3($COMA.line,$COMA.pos,"BIBAN LOS LENGUAJES FUNIZONALES");
                	//  tipo incompatible con el operador aritmetico
                }
            }
        }
	)*
	)?
	;

NEWline          : ('\r'? '\n'|' '|'\t')+  { skip(); };
COMENTARIO       : '/*' .* '*/' {skip();};
COMENTARIOSIMPLE
	:'//' ~('\n'|'\r')* '\r'? '\n' {skip();};
PYC     :';' ;
ASIG    :'=' ;

MAIN 	:'Main';

CLASS   :'class' ;
DOUBLE  :'double';
INT     :'int' ;
BOOL	:'bool';
VOID    :'void';
PRIVATE	:'private';
PUBLIC	:'public';
STATIC	:'static';

RETURN	:'return';

IF	:'if';
ELSE	:'else';
FOREACH	:'foreach';
VAR	:'var';
IN	:'in';

FOR	:'for';
TO	:'to';
STEP	:'step';
WHILE	:'while';
BREAK	:'break';
CONTINUE:'continue';
NEW	:'new';
WRITELINE
	:'System.Console.WriteLine';
READLINE:('int'|'double'|'bool')'.Parse(System.Console.ReadLine())';
PARI    :'(' ;
PARD    :')' ;
LLAVEI  :'{' ;
LLAVED  :'}' ;
CORI	:'[';
CORD	:']';
COMA	:',';
OR	:'|';
AND	:'&';
RELOP	:'=='|'!='|'<'|'>'|'<='|'>=';
ADDOP	:'+'|'-';
MULOP	:'*'|'/';
NOT	:'!';
PUNTO	:'.';
ENTERO  :('0'..'9')+ ;
REAL	:('0'..'9')+'.'('0'..'9')+ ;
BOOLEANO:'True'|'False';
ID      :('a'..'z'|'A'..'Z')('a'..'z'|'A'..'Z'|'0'..'9')*;
